/*
 * LowLevel.h
 *
 *  Created on: Jul 8, 2009
 *      Author: yanir
 */

#ifndef LOWLEVEL_H_
#define LOWLEVEL_H_

#include <fstream>
#include <sstream>
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>


using namespace std;


struct dir{
        char* _file_name;
        int _iNode;
};


class LowLevel {

private:

        int _fd ; //file descriptor for FILE_SYS
        int _pointer_size;
        int _char_size;

        int _free_Inods_p; //points to a location on the free i nodes list.
        int _free_block_p; //points to a location on the free blocks list.

        int _inodes_num; //number of i-nodes
        int _block_size; //block size;
        int _free_blocks_Num;
        int _dataDiskSize;

        int _first_additional_iNods;  // the address of the first additional block of free i nodes addresses (if exists)
        int _first_additional_fBlocks; // the address of the first additional block of free blocks addresses (if exists)

        int _additional_iNodsb; // additional i nodes addresses blocks.
        int _additional_Fb;  //additional free blocks addresses blocks.

public:

        LowLevel();

        virtual ~LowLevel();

        /**
         * allocates a new i-node and returns its number
         */
        int allocateInode();

        /**
         * frees the specified i-node and also frees all the data blocks pointed to by it (directly or indirectly).
         */
        int freeInode(int i_node);

        /**
         *  allocates a data block and returns its number
         */
        int allocateDataBlock();

        /** frees the specified block.
                Use (and update) the maps in the super block in these allocate/free methods. **/
        int freeDataBlock(int dblock);

        /**
         *  return the type of the file (normal/directory/soft-link).
         */
        char getInodeType(int i_node);

        /**
         *  set the type of the file (normal/directory/soft-link).
         */
        int setInodeType(int i_node,char filetype);

        /** return the number of the i-th data block containing the data of this file
         * (for 0<=i<=9 this is just stored in the 10 pointers in this i-node, for i>9, you must retrieve it from the indirect data block..).
         */
        int getDataBlock(int i_node, int i);

        /** sets the i-th data block of this file to be dblockNum.  **/
        int setDataBlock(int i_node, int i, int dblockNum );

        /** read the entire content of the dblockNum's and copy it into buf. **/
        int readBlock(int dblockNum, char* buf);

        /** overwrite the content of block with number dblockNum with the newdata block.
         *  Assume newdata's length is equal to dataBlockSize.
         */
        int writeBlock(int dblockNum, char* newdata);

        /**
         * return the file size saved in the given i-node.This is the exact size of the file in bytes,
         * not the number of blocks used by this file.
         */
        int getFileSize(int i_node);

        /**
         * set the file size.
         */
        int setFileSize(int i_node, int newSize);

        /**
         * gets the i node physical address by the position in the array
         */
        int get_inode_physcal_address(int i);

        /**
         * gets the i node position in the array
         */
        int get_inode_position(int i);

        /**
         * gets the number of hard links of an i node
         */
        int get_hardLinks_num(int i_node);

        /**
         * sets the number of hard links of an i node
         */
        void set_hardLinks_num(int i_node,int hl_num);


        /**
         * write dir to a datablock
         */
        int write_dir(int dblockNum,int i_node,char* dirName,int position);

        /**
         * returns a dir content
         */
        dir* read_dir(int dblockNum,int i_node,int position);

        /** sets the root i node to be i_node **/
        void set_root_iNode(int i_node);

        /** gets the root i node **/
        int get_root_iNode();



        int calculate_additional_block();

        void set_additionals();

        int handle_iNode_aloc(int position);

        int handle_block_aloc(int position);

        void handle_iNodeFree(int position,int iNode_address);

        void handle_freeBlock(int position,int block_address);

        int check_space();

////////////////////// GETTERS AND SETTERS /////////////////////////

         int getFd() const
            {
                return _fd;
            }

            void setFd(int _fd)
            {
                this->_fd = _fd;
            }

            int getPointer_size() const
            {
                return _pointer_size;
            }

            void setPointer_size(int _pointer_size)
            {
                this->_pointer_size = _pointer_size;
            }

            int getChar_size() const
            {
                return _char_size;
            }

            void setChar_size(int _char_size)
            {
                this->_char_size = _char_size;
            }

            int getFree_Inods_p() const
            {
                return _free_Inods_p;
            }

            void setFree_Inods_p(int _free_Inods_p)
            {
                this->_free_Inods_p = _free_Inods_p;
            }

            int getFree_block_p() const
            {
                return _free_block_p;
            }

            void setFree_block_p(int _free_block_p)
            {
                this->_free_block_p = _free_block_p;
            }

            int getInodes_num() const
            {
                return _inodes_num;
            }

            void setInodes_num(int _inodes_num)
            {
                this->_inodes_num = _inodes_num;
            }

            int getBlock_size() const
            {
                return _block_size;
            }

            void setBlock_size(int _block_size)
            {
                this->_block_size = _block_size;
            }

            int getFree_blocks_Num() const
            {
                return _free_blocks_Num;
            }

            void setFree_blocks_Num(int _free_blocks_Num)
            {
                this->_free_blocks_Num = _free_blocks_Num;
            }

            int getDataDiskSize() const
            {
                return _dataDiskSize;
            }

            void setDataDiskSize(int _dataDiskSize)
            {
                this->_dataDiskSize = _dataDiskSize;
            }

            int getFirst_additional_iNods() const
            {
                return _first_additional_iNods;
            }

            void setFirst_additional_iNods(int _first_additional_iNods)
            {
                this->_first_additional_iNods = _first_additional_iNods;
            }

            int getFirst_additional_fBlocks() const
            {
                return _first_additional_fBlocks;
            }

            void setFirst_additional_fBlocks(int _first_additional_fBlocks)
            {
                this->_first_additional_fBlocks = _first_additional_fBlocks;
            }

            int getAdditional_iNodsb() const
            {
                return _additional_iNodsb;
            }

            void setAdditional_iNodsb(int _additional_iNodsb)
            {
                this->_additional_iNodsb = _additional_iNodsb;
            }

            int getAdditional_Fb() const
            {
                return _additional_Fb;
            }

            void setAdditional_Fb(int _additional_Fb)
            {
                this->_additional_Fb = _additional_Fb;
            }




};

#endif /* LOWLEVEL_H_ */
